<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
<script>

    // 2. 函数版(简易工厂模式)
    // 优点 => 可以根据给定参数快速生成对
    // 缺点:
    // 1. 通过函数创建的对象和函数没有关系  => 不是通过构造函数创建的
    // 2. 公有的属性和方法重复声明 => 占内存

   /*  function cat(name,color) {
        var obj = { // 字面量对象 => new Object
            name: name,
            color: color,
            species: "Cat",
            skill() {
                console.log("捉老鼠");
            },
            call() {
                console.log("喵喵");
            }
        }
        return obj;
    }

    var Tom = cat("Tom","black");
    console.log(Tom);

    var Kitty = cat("Kitty","pink");
    console.log(Kitty);

    var Duola = cat("Duola","blue");
    console.log(Duola); */



    // 构造函数版
    // 1. 通过构造函数创建对象(实例化对象) => 根构造函数有关系

    // 但是此写法公有的属性和方法 => 还是重复创建 => 占内存

    function Cat(name,color) {
        // {}
        // this -> {};

        // 我们在自定义构造函数过程中 所做的操作  => 将属性和方法通过this绑定到实例化对象上
        this.name = name;
        this.color = color;

        // 公有的属性和方法 => 还是重复创建 => 占内存
        // this.species = "Cat";
        // this.skill = function(){
        //     console.log("捉老鼠");
        // }

        // this.call = function(){
        //     console.log("喵喵");
        // }

        // return this;
    }

    // 既然是公共的属性和方法 => 没有必要每个实例化对象都存储一遍 ? 
    
    // 解决方法
    // 把实例化对象公有属性和方法提取出来, 存在一个公共的位置 => 允许所有的实例化对象(该构造函数创建的)访问
    
    // 注意:
    // 1. 函数也是一个特殊的对象
    // 2. 构造函数存在prototype属性(属性值是一个对象) => 原型对象 => 官方提供,专门用于给构造函数使用, 存储实例化对象的公有属性和方法  (其实普通函数也有prototype  => 普通函数也有成为构造函数的潜力)
    console.dir(Cat);


    // prototype => 原型对象
    // 把实例化对象公有属性和方法提取出来, 存在一个公共的位置(构造函数.prototype) => 允许所有的实例化对象访问
    Cat.prototype.species = "Cat";
    Cat.prototype.skill = function(){
        console.log("捉老鼠");
    }
    Cat.prototype.call = function(){
        console.log("喵喵");
    }

    // 关于prototype上 函数的this指向
    // 虽然此方法存储在在构造函数Cat的原型对象上(Cat.prototype),但是是给所有的实例化对象访问的 (Tom.say() Kitty.say())   => 根据this指向(函数在调用时属于谁就指向谁)
    
    // 原型对象上的公共方法中 => this指向调用此方法的实例化对象
    Cat.prototype.say = function(){
        //  this -> 调用此方法的实例化对象
        console.log("this",this);
        console.log(this.name,this.color);
    }

    console.dir(Cat);


    // 实例化对象访问属性和方法的顺序:
    // 1. 实例化对象自己有 =>  就访问自己的
    // 2. 自己没有就找构造函数原型对象上的公有属性和方法(公共的)
    var Tom = new Cat("Tom","black");
    console.log(Tom, Tom instanceof Cat);
    
    // 1. 实例化对象自己有 =>  就访问自己的
    // console.log(Tom.name,Tom.color);

    // 2. 自己没有就找构造函数原型对象上的属性和方法(公共的)
    // console.log(Tom.species);
    // console.log(Tom.skill);
    // console.log(Tom.call);
    // Tom.skill();  //先取值(Tom.skill) 在调用Tom.skill()

    Tom.say();


    var Kitty = new Cat("Kitty","pink");
    console.log(Kitty);

    Kitty.say();

    var Duola = new Cat("Duola","blue");
    console.log(Duola);

    Duola.say();


</script>
</html>